/* eslint  no-param-reassign: "off" */
import 'intersection-observer';
// import log from '../lib/log';
import { getMVData } from '../lib/dom-data';
import { querySelectorAll, debounce } from '../lib/tools';
import { viewConfig, Config } from '../lib/types';
import { setViewConfig } from '../lib/config';

// 监听view点元素
export function addViewListener(viewConf: Config) {
  let documentObserve: IntersectionObserver;
  let viewEleList: Element[];

  // 监听view点元素
  function addViewElementObserver(viewList: Element[]) {
    viewList.forEach((currentNode: Element) => { documentObserve.observe(currentNode); });
  }

  // 解除监听
  function delViewElementObserver(viewList: Element[]) {
    viewList.forEach((currentNode) => { documentObserve.unobserve(currentNode); });
  }

  function amutationCallbackV2() {
    // const startTime: number = Date.now();
    const { viewAttr } = viewConf;
    const viewList = querySelectorAll(`[${viewAttr}]`);
    const validList: Element[] = [];
    const insertList: Element[] = [];
    viewList.forEach((currentNode) => {
      const index = viewEleList.indexOf(currentNode);
      if (index > -1) {
        validList.push(currentNode);
        viewEleList.splice(index, 1);
      } else {
        insertList.push(currentNode);
      }
    });
    delViewElementObserver(viewEleList);
    addViewElementObserver(insertList);
    viewEleList = validList.concat(insertList);
    // if (debug) log.info('Duration of mutationCallback execution: ', Date.now() - startTime);
  }

  // 包含一个或多个匹配的选择器, 可以通过使用逗号分隔多个选择器来指定
  function mutationListener() {
    const { selectors } = viewConf;
    if (selectors && typeof MutationObserver === 'function') {
      const observerOptions: MutationObserverInit = {
        childList: true, // 添加或删除新节点触发回调
        attributes: false, // 观察属性变动
        characterData: false, // 节点内容或节点文本的变动
        subtree: true, // 监视目标节点及其所有后代
      };
      const observer = new MutationObserver(debounce(amutationCallbackV2, 50));
      let nodeList;
      if (selectors === true) {
        nodeList = [document.body];
      } else if (typeof selectors === 'string') {
        nodeList = querySelectorAll(selectors);
      } else if (Array.isArray(selectors)) {
        nodeList = selectors;
      } else if (typeof selectors === 'object' && selectors.nodeType === 1) {
        nodeList = [selectors];
      } else {
        throw new Error('selectors is an illegal parameter');
      }
      nodeList.forEach((node) => {
        observer.observe(node, observerOptions);
      });
    }
  }

  // 元素在可见监听区域其可见部分穿过了一个或多个阈(thresholds)时，会执行指定的回调函数
  function viewHandle(entries: IntersectionObserverEntry[]) {
    entries.forEach((entry) => {
      const currentNode = entry.target;
      const mvData = getMVData(currentNode, viewConf);
      // 有上报配置
      if (mvData) {
        const { config } = mvData;
        // 不限制上报次数，或者上报次数为达到限制值
        if (!config.viewCount || config.count < config.viewCount) {
          // 元素在视口内占比是否达标
          if (entry.isIntersecting) {
            if (config.viewDuration === 0) {
              // 符合打点条件
              viewConf.sendViewData && viewConf.sendViewData(mvData, viewConf);
              config.count += 1;
            } else {
              config.viewCallback = window.setTimeout(() => {
                viewConf.sendViewData && viewConf.sendViewData(mvData, viewConf);
                mvData.config.count += 1;
              }, config.viewDuration);
            }
          } else if (config.viewCallback) {
            clearTimeout(config.viewCallback);
          }
        }
      }
    });
  }

  const { threshold, root } = viewConf;
  const options: IntersectionObserverInit = {
    threshold: threshold || 0, // 设置触发回调的临界值， 用来指定交叉比例，决定什么时候触发回调函数，是一个数组，默认是[0]
    root, // 用于观察的根元素，默认是浏览器的视口，也可以指定具体元素，指定元素的时候用于观察的元素必须是指定元素的子元素
  };
  // 实例化
  documentObserve = new IntersectionObserver(viewHandle, options);
  // 监听所有view点元素
  viewEleList = querySelectorAll(`[${viewConf.viewAttr}]`);
  addViewElementObserver(viewEleList);
  // 监听全局或者局部地区元素的增删变动
  mutationListener();
}

// 初始化fish view配置，开启view监听
export default function initView(options: viewConfig = {}) {
  const config: Config = setViewConfig(options);
  if (typeof window !== 'object') return;
  addViewListener(config);
}

// function mutationCallbackV1(mutationsList: MutationRecord[]) { // : Element[]
//   const startTime: number = Date.now();
//   const { debug, viewAttr } = config;
//   debug && log.info('Run mutation event callback', mutationsList);
//   let addedList: Element[] = [];
//   let removedList: Element[] = [];
//   mutationsList.forEach((mutation: MutationRecord) => {
//     if (mutation.addedNodes.length) addedList = addedList.concat(filterElement(mutation.addedNodes, viewAttr as string));
//     if (mutation.removedNodes.length) removedList = removedList.concat(filterElement(mutation.removedNodes, viewAttr as string));
//   });
//   if (removedList.length) {
//     removedList.forEach((node: Element) => {
//       const index = viewEleList.indexOf(node);
//       if (index > -1) viewEleList.splice(index, 1);
//     });
//     delViewElementObserver(removedList);
//   }
//   if (addedList.length) {
//     addedList = unique(addedList);
//     viewEleList = viewEleList.concat(addedList);
//     addViewElementObserver(addedList);
//   }
//   if (debug && (addedList.length || removedList.length)) {
//     const domCount: number = querySelectorAll(`[${viewAttr}]`).length;
//     if (domCount === viewEleList.length) {
//       log.info('Total number of listening elements: ', viewEleList.length);
//     } else {
//       log.err(`The number of view elements is different from the number of actual listeners; view elements: ${domCount}, Listening element: ${viewEleList.length}`);
//     }
//   }
//   debug && log.info('Duration of mutationCallbackV! execution: ', Date.now() - startTime);
// }


// function addViewElementObserver() {
//   const queryStartTime: number = Date.now();
//   documentObserve.disconnect();
//   // 查询所有需要被监听的元素
//   const viewEleList: Element[] = querySelectorAll(`[${viewConf.viewAttr}]`);
//   viewEleList.forEach((currentNode: Element) => { documentObserve.observe(currentNode); });
//   viewConf.debug && log.info('addViewElementObserver duration: ', Date.now() - queryStartTime);
// }

// function nodeFilter(list: NodeList): boolean {
//   for (let i: number = 0; i < list.length; i++) {
//     if (list[i].nodeType === 1) return true;
//   }
//   return false;
// }

// function amutationCallbackV3(mutationsList: MutationRecord[]) {
//   viewConf.debug && log.info('Run mutation event callback', mutationsList);
//   for (let i: number = 0; i < mutationsList.length; i++) {
//     const mutation: MutationRecord = mutationsList[i];
//     if (nodeFilter(mutation.addedNodes) || nodeFilter(mutation.removedNodes)) {
//       addViewElementObserver();
//       break;
//     }
//   }
// }
